(function (root, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
        typeof define === 'function' && define.amd ? define(['exports'], factory) :
            (global = typeof globalThis !== 'undefined' ? globalThis : window.global = window || self, factory(global.MeshSDK = {}));
}(this,
    function (exports) {
        'use strict';
        var Protocal = (function () {
            function Protocal(methodName, id, params, onComplete, onReceive, timeout) {
                var _this = this;
                var key = methodName + "_" + id;
                this._receiveName = key + "_receive";
                this._completeName = key + "_complete";
                params = params || {};
                params['receive'] = this._receiveName;
                params['jsCallback'] = this._completeName;
                if (methodName !== 'sendGameAction' && params.type !== 5) {
                    console.log('[MeshH5]', 'params', params);
                }
                window[this._receiveName] = function (result) {
                    console.log('[MeshH5]', 'native:', "methodName " + key + " received");
                    window[_this._receiveName] = null;
                    _this.done();
                    if (onReceive) {
                        onReceive(null, result);
                    }
                };
                var flag = false;
                window[this._completeName] = function (result) {
                    console.log('[MeshH5]', 'native:', "methodName " + key + " completed", result);
                    flag = true;
                    _this.dispose();
                    if (onComplete) {
                        onComplete(null, result);
                    }
                };
                if (Utils.isIframe()) {
                    if (methodName == 'sendGameAction') {
                        if (params.type == 1) {
                            flag = true;
                            _this.dispose();
                            return;
                        }
                    }
                    window.addEventListener('message', e => {
                        if (e.data && window[this._completeName]) {
                            var data = e.data;
                            var jsMethods = data.jsMethods;
                            if (!jsMethods) return;
                            if (jsMethods !== this._completeName) return;
                            var jsData = data.jsData;
                            if (!jsData) return;
                            var result = MeshSDK.prototype.parseResult(undefined, jsData);
                            if (!result)
                                return;
                            console.log('[MeshH5]', 'iFrame:', "methodName " + jsMethods + " completed", result);
                            flag = true;
                            _this.dispose();
                            if (onComplete) {
                                onComplete(null, result);
                            }
                        }
                    }, false);
                }
                if (timeout > 0) {
                    this._completeTimeoutId = setTimeout(function () {
                        clearTimeout(_this._completeTimeoutId);
                        if (onComplete && !flag) {
                            _this.dispose();
                            onComplete("methodName " + key + " not responding", null);
                        }
                    }, timeout);
                }
            }

            Protocal.prototype.onDone = function (callback) {
                if (this._receiveName && this._completeName)
                    this._onDone = callback;
            };
            Protocal.prototype.done = function () {
                if (this._onDone) {
                    this._onDone();
                    this._onDone = undefined;
                }
            };
            Protocal.prototype.dispose = function () {
                this.done();
                window[this._receiveName] = null;
                delete window[this._receiveName];
                this._receiveName = null;
                window[this._completeName] = null;
                delete window[this._completeName];
                this._completeName = null;
                clearTimeout(this._completeTimeoutId);
            };
            Protocal.TIME_OUT_IN_MS = 1500;
            return Protocal;
        }());
        var Native = (function () {
            function Native() {
            }

            Native.invoke = function (methodName, protocal, params, onComplete, onReceive, timeout
            ) {
                var _this = this;
                if (timeout === void 0) {
                    timeout = 5000;
                }
                var proto = this.createProtocal(methodName, params, onComplete, onReceive, timeout);
                if (proto) {
                    var isIframe = Utils.isIframe();
                    if (Utils.isAndroid()) {
                        if (isIframe) {
                            console.log('android iframe');
                            //向iframe发送消息
                            window.parent.postMessage(JSON.stringify(params), "*");
                        } else {
                            if (protocal) {
                                if (Utils.isUnity()) {
                                    protocal.call(window.Unity, JSON.stringify(params));
                                } else {
                                    protocal.call(window.NativeBridge, JSON.stringify(params));
                                }
                            }
                        }
                    } else if (Utils.isIOS()) {
                        if (isIframe) {
                            console.log('ios iframe');
                            //向iframe发送消息
                            window.parent.postMessage(JSON.stringify(params), "*");
                        } else {
                            if (protocal) {
                                protocal.postMessage(JSON.stringify(params));
                            }
                        }
                    } else {
                        if (isIframe) {
                            console.log('pc iframe');
                            //向iframe发送消息
                            window.parent.postMessage(JSON.stringify(params), "*");
                        } else {
                            console.error('[MeshH5]', 'native:', 'invalid Android&Ios');
                        }
                    }
                } else {
                    console.error('[MeshH5]', 'native:', 'invalid protocal initliazation');
                }
            };
            Native.createProtocal = function (methodName, params, onComplete, onReceive, timeout) {
                var total = this.PROTOCAL_CACHE[methodName] || 0;
                total += 1;
                this.PROTOCAL_CACHE[methodName] = total;
                return new Protocal(methodName, total, params, onComplete, onReceive, timeout);
            };
            Native._allIFrames = [];
            Native._iframeId = -1;
            Native.PROTOCAL_CACHE = {};
            return Native;
        }());
        var isAndroid = function () {
            var u = navigator.userAgent;
            return u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;
        };
        var isIOS = function () {
            var u = navigator.userAgent;
            return !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
        };
        var isIframe = function () {
            return window.top !== window;
        };
        var isUnity = function () {
            return window['isUnity'];
        }
        var nativeCall = Native.invoke.bind(Native);
        var Utils = Object.freeze({
            nativeCall: nativeCall,
            isAndroid: isAndroid,
            isIOS: isIOS,
            isIframe: isIframe,
            isUnity: isUnity,
        });
        var MeshSDK = (function () {
            function MeshSDK() {
                /*注册H5接受消息*/
                this._wrappedConfigParams = {
                    //用户token发生变化
                    'serverCodeUpdate': function (handler, result) {
                        var cb = handler, data = result;
                        if (cb) {
                            cb(data);
                        }
                    },
                    //用户货币发生变化
                    'walletUpdate': function (handler, result) {
                        var cb = handler, data = result;
                        if (cb) {
                            cb(data);
                        }
                    },
                    /**
                     * 游戏行为发生变化
                     * 物理返回键:{
                     *     type:1
                     * }
                     * 返回按钮显示状态:{
                     *     type:2,
                     *     showStatus:0 隐藏 1 显示
                     * }
                     * 观众人数变化:{
                     *     type:3,
                     *     audienceCount:1//最新观众人数
                     * }
                     * APP操作游戏座位
                     *      1.收到sendGameAction 上/下游戏座位 type:15
                     *      2.通过APP麦位上座游戏座位(按需调用)
                     *      3.收到sendGameAction 同步座位信息 type:16 时，发现座位信息同麦位信息不一致时，
                     *        以APP麦位信息为准，进而保证两者的一致性。(按需调用)
                     * :{
                     *      type:4,
                     *      params:{
                     *          optType:0,//0上座,1下座
                     *          userId:xxxA,
                     *          seat:0 // 座位位置
                     *      }
                     * }
                     * 变更用户身份
                     * {
                     *     type:5,
                     *     params:{
                     *         role:0,//0.正常用户 1.游客  2.主持人(拥有开始游戏权限)
                     *         userId:xxxA
                     *     }
                     * }
                     * APP返回踢人操作结果
                     * {
                     *     type:6,
                     *     params:{
                     *         optResult:0,//0 踢人成功 1 踢人失败
                     *         optUserId:0,//执行踢人操作用户id
                     *         userId:xxxA,//被踢用户id
                     *         reason:"success" //optResult 为1时，需要注明原因
                     *     }
                     * }
                     * @param handler
                     * @param result
                     * 活动入口ICON状态 (psd):
                     * {
                     *     type:2001,
                     *     showStatus:0 隐藏 1 显示
                     *     activityIcon:'' 活动icon 外网访问地址 (120*120 px)
                     * }
                     *
                     * 打开帮助
                     * {
                     *     type:2002
                     * }
                     *
                     * 控制游戏背景音乐 0-1
                     * {
                     *     type:2003,
                     *     bgVolume:0.5
                     * }
                     *
                     * 控制游戏音效 0-1
                     * {
                     *     type:2004,
                     *     soundVolume:0.5
                     * }
                     *
                     * 麦位图标底部到屏幕顶部距离/屏幕高度
                     * 数值范围 0-1
                     * {
                     *     type:2005,
                     *     value:0.1
                     * }
                     *
                     * 帮助按钮显示状态:{
                     *     type:2006,
                     *     showStatus:0 隐藏 1 显示
                     * }
                     *
                     * musee 最小化按钮显示状态:{
                     *     type:2007,
                     *     showStatus:0 隐藏 1 显示
                     * }
                     * 客户端通知游戏最小化状态
                     * {
                     *     type:2008,
                     *     minimizeStatus:0 取消最小化 1 启用最小化
                     * }
                     * tietie 控制游戏内的按钮点击逻辑
                     * {
                     *   type:2009,
                     *   params:{
                     *       "subAction":2009,
                     *       "subMsg":{}
                     *   }
                     * }
                     * 切换货币
                     * {
                     *     type:2010,
                     *     params:{
                     *          appId:xxx,
                     *          coinType:1
                     *      }
                     * }
                     * 隐藏设置按钮和商城按钮
                     * {
                     *     type:2011,
                     *     params:{
                     *         "settingButton": false,  //设置按钮是否隐藏（true显示，false隐藏，默认显示）
                     *         "mallButton": false, //商城按钮是否隐藏（true显示，false隐藏，默认显示）
                     *         "subMsg": {} //保留字段可不传
                     *     }
                     * }
                     * 查询当前音乐和音效的状态
                     * {
                     *     type:2012,
                     *     params:{}
                     * }
                     * 直接触发游戏内的事件（拉起商城、拉起规则页）
                     * {
                     *     type:2013,
                     *     params:{
                     *         //1001 拉起规则页面  //1002拉起商城页面 //1003设置音效和音乐相关的
                     *         "subAction": 1001,
                     *         "subMsg": {
                     *                     //在subAction为 1003 的时候传bgmStatus、seStatus字段
                     *                     "bgmStatus": 1, //背景音乐 bgmStatus 0 关闭 1 打开
                     *                     "seStatus": 1 //音效 seStatus 0 关闭 1 打开
                     *                   }
                     *     }
                     * }
                     */

                    'gameActionUpdate': function (handler, result) {
                        var cb = handler, data = result;
                        if (cb) {
                            cb(data);
                        }
                    },
                    /**
                     * 声音发生变化
                     * 背景音乐 bgmStatus 0 关闭 1 打开
                     * 音效 seStatus 0 关闭 1 打开
                     * {bgmStatus:1,seStatus:1}
                     * @param handler
                     * @param result
                     */
                    'soundUpdate': function (handler, result) {
                        var cb = handler, data = result;
                        if (cb) {
                            cb(data);
                        }
                    },
                    /**
                     * musee 恢复游戏面板
                     * 游戏 恢复音量
                     */
                    'openFoldGame': function (handler, result) {
                        var cb = handler, data = result;
                        if (cb) {
                            cb(data);
                        }
                    },
                }
            }

            /**
             * 创建协议
             * @param fnName 方法名
             */
            MeshSDK.prototype.createProtocol = function (fnName) {
                var isIframe = Utils.isIframe();
                if (Utils.isAndroid()) {
                    if (isIframe) {
                        console.log('android iframe');
                    } else if (Utils.isUnity()) {
                        if (window.Unity && window.Unity['call']) {
                            return window.Unity['call'];
                        } else {
                            return null;
                        }
                    } else {
                        if (window.NativeBridge && window.NativeBridge[fnName]) {
                            return window.NativeBridge[fnName];
                        } else {
                            return null;
                        }
                    }
                } else if (Utils.isIOS()) {
                    if (isIframe) {
                        console.log('ios iframe');
                    } else if (Utils.isUnity()) {
                        if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers['unityControl']) {
                            return window.webkit.messageHandlers['unityControl'];
                        } else {
                            return null;
                        }
                    } else {
                        if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers[fnName]) {
                            return window.webkit.messageHandlers[fnName];
                        } else {
                            return null;
                        }
                    }
                } else {
                    if (isIframe) {
                        console.log('pc iframe');
                    } else {
                        console.error('[Mesh-H5-sdk]', "createProtocol 既不是Andoroid也不是Ios");
                    }
                }
            };
            /**
             * 通用的处理结果的方法
             * @param err 错误信息
             * @param result 成功的结果，一般是字符串，需要JSON.parse处理
             * @returns {*}
             */
            MeshSDK.prototype.parseResult = function (err, result) {
                if (err)
                    throw err;
                else if (result == undefined || result == null)
                    throw 'empty result';
                else {
                    var parsed = void 0;
                    if (typeof result == 'string') {
                        parsed = JSON.parse(result);
                    } else if (typeof result == 'object') {
                        parsed = result;
                    }
                    if (!parsed)
                        throw 'failed to parse';
                    return parsed;
                }
            };
            /**
             * 辅助方法，用来方便创建统一的协议回调处理逻辑
             * @param resolve 通过 promise 传入的 resolve 回调
             * @param reject 通过 promise 传入的 reject 回调
             */
            MeshSDK.prototype.usePromiseResult = function (resolve, reject) {
                var _this = this;
                return function (err, result) {
                    try {
                        var parsed = _this.parseResult(err, result);
                        if (parsed) {
                            resolve(parsed);
                        }
                    } catch (e) {
                        reject(e);
                    }
                };
            };
            /**
             * 发送协议的接口。
             * 一般情况下无需主动调用
             * @param params 构造出来的协议参数，包括协议名和参数等
             * @param onComplete 完成回调
             * @param onReceive 接收到回调
             */
            MeshSDK.prototype.send = function (params, onComplete, onReceive) {
                if (!params)
                    return;
                Utils.nativeCall(params.methodName, params.protocol, params.params, onComplete, onReceive, params.timeout);
            };
            /**
             * 通用的请求协议的方法。可以参照协议文档进行调用。
             * @param methodName 方法函数名
             * @param params 协议参数，JSON Object
             * @param onComplete 协议完成回调方法
             * @param onReceived 协议收到回调方法（ACK）
             * @param timeout 超时，单位毫秒。默认 0 为不超时。超时设置的用处是清空回调等资源。
             */
            MeshSDK.prototype.request = function (methodName, params, onComplete, onReceived, timeout) {
                if (timeout === void 0) {
                    timeout = 0;
                }
                this.send({
                    methodName: methodName,
                    protocol: this.createProtocol(methodName),
                    params: params,
                    timeout: timeout,
                }, this.usePromiseResult(onComplete, function (reason) {
                    return console.error('[Mesh-H5-sdk]', "methodName " + methodName + " error: " + reason);
                }), onReceived);
            };
            MeshSDK.prototype.regReceiveMessage = function (params) {
                var _this = this;
                var wrapped = {};
                for (var key in params) {
                    if (!!_this._wrappedConfigParams[key]) {
                        wrapped[key] = key;
                    }
                }
                if (Utils.isIframe()) {
                    window.addEventListener('message', e => {
                        if (e.data) {
                            var data = e.data;
                            var jsMethods = data.jsMethods;
                            if (!params[jsMethods])
                                return;
                            var jsData = data.jsData;
                            if (!jsData) return;
                            var result = MeshSDK.prototype.parseResult(undefined, jsData);
                            if (!result)
                                return;
                            if (typeof params[jsMethods] === 'function' || !!_this._wrappedConfigParams[jsMethods]) {
                                _this._wrappedConfigParams[jsMethods](params[jsMethods], result);
                            }
                        }
                    });
                } else {
                    // 把包裹后的方法注册到 window 上
                    Object.keys(wrapped).forEach(function (key) {
                        var name = wrapped[key];
                        if (name) {
                            if (name == 'openFoldGame') {
                                window[name] = function (str) {
                                    if (typeof params[key] === 'function' || !!_this._wrappedConfigParams[key]) {
                                        _this._wrappedConfigParams[key](params[key], {});
                                    }
                                }
                            } else {
                                window[name] = function (str) {
                                    var result = _this.parseResult(undefined, str);
                                    if (!result)
                                        return;
                                    if (!params[key])
                                        return;
                                    if (typeof params[key] === 'function' || !!_this._wrappedConfigParams[key]) {
                                        _this._wrappedConfigParams[key](params[key], result);
                                    }
                                };
                            }
                        }
                    });
                }
                return wrapped;
            };
            /**
             * 获取版本号(H5SDK 协议)
             * @returns {Promise<unknown>}
             */
            MeshSDK.prototype.getVersion = function () {
                return new Promise(function (resolve) {
                    var data = "1.0.0";
                    resolve(data);
                });
            };
            /**
             * 获取用户信息配置
             * @returns {Promise<unknown>}
             */
            MeshSDK.prototype.getConfig = function () {
                var _this = this;
                return new Promise(function (resolve, reject) {
                    _this.request("getConfig", {}, function (data) {
                        resolve(data);
                    }, reject);
                });
            };
            /**
             * 销毁游戏
             * @returns {Promise<unknown>}
             */
            MeshSDK.prototype.destroy = function () {
                var _this = this;
                return new Promise(function (resolve, reject) {
                    _this.request("destroy", {}, function (data) {
                        resolve(data);
                    }, reject);
                });
            };
            /**
             * 提示余额不足，拉起充值商城
             * type 0：余额不足 1：余额充足，主动调用
             * gameId：游戏Id
             * paymentType
             *   trovo: 1: mana; 2: game coin
             *   musee: 1:黄钻 2:蓝钻
             * inThisRound: 本轮是否参与 0:未参与  1:参与
             * @returns {Promise<unknown>}
             */
            MeshSDK.prototype.gameRecharge = function (params) {
                var _this = this;
                return new Promise(function (resolve, reject) {
                    _this.request("gameRecharge", params ? params : {}, function (data) {
                        resolve(data);
                    }, reject);
                });
            };
            /**
             * 游戏加载完毕
             * @returns {Promise<unknown>}
             */
            MeshSDK.prototype.gameLoaded = function () {
                var _this = this;
                return new Promise(function (resolve, reject) {
                    _this.request("gameLoaded", {}, function (data) {
                        resolve(data);
                    }, reject);
                });
            };
            /**
             * musee
             * 最小化按钮
             * 调用时游戏执行静音操作(不再执行，只是通知到最小化操作)
             * @returns {Promise<unknown>}
             */
            MeshSDK.prototype.foldGame = function () {
                var _this = this;
                return new Promise(function (resolve, reject) {
                    _this.request("foldGame", {}, function (data) {
                        resolve(data);
                    }, reject);
                });
            };

            /**
             * 上报游戏行为
             * 游戏加载进度  type:1, params: {progress: 10}
             * 进入/打开游戏主页 type:2
             * 游戏房间号 type:3, params: {gameRoomId: 'xxxx'}
             * 网络延迟程度
             *   type:4,
             *   params:{
             *       status:1,延迟程度(1:良好 0~100ms,2:普通 100~200ms,3:较差 200~300ms,4:很差 300~600ms,5:极差 >600ms,6:断开网络 9999ms)
             *       latency:100,延迟时间，单位ms
             *   }
             * 帧率
             *   type:5,
             *   params:{
             *       status:1,帧率评级(1:超高 >60fps,2:高 50~60fps,3:中 30~50fps,4:较低 20~30fps,5:低 <20fps)
             *       fps:55,帧率值
             *   }
             * 拉起观众列表 type:6
             * 拉起玩家资料卡 type:7,params:{userId:xxx}
             * 获取用户是否已关注
             *    type:8,params:{userIds:[userId1xx,userId2xx]}
             *    返回数据：{
             *              userIds:{userId1xx:true,userId2xx:false}//true为已关注
             *            }
             * 关注用户
             *    type:9,params:{userId:xxx}
             *    返回数据：{
             *        status:0,//0 为关注成功,1 为关注失败
             *        userId:xxx,
             *    }
             * 拉起分享面板 type:10
             * 回到APP准备页(组队页) type:11
             * 点击右上角关闭按钮 type:12
             * 游戏开始 type:13
             * 游戏结束 type:14
             * 上/下游戏座位
             *    type:15
             *    params:{
             *        optType:0,//0上座,1下座
             *        userId:xxxA,
             *        seat:0 // 座位位置
             *    }
             * 同步座位信息
             *    type:16,
             *    params:{
             *      seats:[
             *          {
             *              userId:xxxA,
             *              seat:0, //座位位置
             *              prepareStatus:0 //0未准备,1已准备
             *          },
             *          {
             *              userId:xxxB,
             *              seat:1,
             *              prepareStatus:1,
             *          }
             *      ]
             *    }
             * 游戏发起踢人请求
             *    type:17,
             *    params:{
             *      userId:xxxA,
             *      seat:0 //座位位置
             *    }
             * 游戏上座失败
             *    type:18,
             *    params:{
             *        userId:xxxA,
             *    }
             * 是否可切换货币，游戏打开时状态为不可以切换
             *    type:19,
             *    params:{
             *        isCanChange: 0 不可切换 1 可切换
             *        currencyCoinType:1,//当前货币类型
             *    }
             * 语聊房游戏准备完成，通知 app 可以发起自动上座 type:20
             * 返回游戏内的音乐和音效状态（一般是收到gameActionUpdate中的 type ==2012 的时候发起回调）
             *    type: 21,
             *    params: {
             *         "bgmStatus": 1, //背景音乐 bgmStatus 0 关闭 1 打开
             *         "seStatus": 1   //音效 seStatus 0 关闭 1 打开
             *    }
             * 触发活动事件 psd专享()
             *    type:2001
             * 帮助页准备完毕
             *    type:2002
             *    params:{
             *        url:""
             *    }
             * 通知miya H5商城事件
             *  type:2003
             *  params:{
             *        env: 1 //1测试,2正式
             *        gameId:xxx
             *    }
             * 同步APP 麦克风和扬声器开关 游戏内通知 (比如拆弹猫、谁是卧底等）
             * {
             *     "type":3001,
             *     "params": {
             *         "users": [
             *                 {
             *                     "userId:": "xxxxx",   //用户 id
             *                     "microphone": false, //是否开启麦克风  false关闭  true开启
             *                     "useSpeaker": false //是否开启扬声器
             *                 },
             *                 {
             *                     "userId:": "xxxxx",
             *                     "microphone": true,
             *                     "useSpeaker": true
             *                 }
             *             ]
             *     }
             * }
             *
             * {
             *   "type": 3002,
             *   "params": {
             *     "state": 0 //0 代表点击的结算页面的关闭按钮   1 代表点击结算页面的再来一局按钮
             *   }
             * }
             * @returns {Promise<unknown>}
             */
            MeshSDK.prototype.sendGameAction = function (params) {
                var _this = this;
                return new Promise(function (resolve, reject) {
                    _this.request("sendGameAction", params, function (data) {
                        resolve(data);
                    }, reject);
                });
            };

            /**
             * 是否支持isSupportRechargeV2
             * trovo 使用
             * @returns
             * isSupport boolean
             * true 去掉之前的Toast提示，调用gameRecharge paymentType =1
             * false 保留Toast
             */
            MeshSDK.prototype.isSupportRechargeV2 = function () {
                var _this = this;
                return new Promise(function (resolve) {
                    var isSupport = false;
                    if (Utils.isAndroid()) {
                        if (window.NativeBridge['versionSupportApis']) {
                            _this.request("versionSupportApis", {}, function (data) {
                                if (data.apis && data.apis.includes('gameRechargeV2_trovo')) {
                                    isSupport = true;
                                }
                                resolve({'isSupport': isSupport});
                            });
                        } else {
                            resolve({'isSupport': isSupport});
                        }
                    } else if (Utils.isIOS()) {
                        if (window.webkit.messageHandlers['versionSupportApis']) {
                            _this.request("versionSupportApis", {}, function (data) {
                                if (data.apis && data.apis.includes('gameRechargeV2_trovo')) {
                                    isSupport = true;
                                }
                                resolve({'isSupport': isSupport});
                            });
                        } else {
                            resolve({'isSupport': isSupport});
                        }
                    } else {
                        isSupport = true;
                        resolve({'isSupport': isSupport});
                    }
                });
            };

            return MeshSDK;
        }());
        var meshSDK = new MeshSDK();
        exports.meshSDK = meshSDK;
        Object.defineProperty(exports, '__esModule', {value: true});
    }));